//
// Created by zhupi on 2024/10/30.
//

#ifndef DEMO2_BASE_TABLE_WIDGET_H
#define DEMO2_BASE_TABLE_WIDGET_H


#include <QTableWidget>
#include <QKeyEvent>
#include <QMessageBox>
#include <QTimer>

#include <QStyledItemDelegate>
#include <QIntValidator>
#include <QDoubleValidator>
#include <QLineEdit>

class NumericDelegate : public QStyledItemDelegate {
Q_OBJECT

public:
    enum DataType { IntegerType, DoubleType };

    NumericDelegate(DataType type, QObject *parent = nullptr)
            : QStyledItemDelegate(parent), type_(type) {}

    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
        QLineEdit *editor = new QLineEdit(parent);
        if (type_ == IntegerType) {
            QIntValidator *intValidator = new QIntValidator(1, INT_MAX, editor);  // 禁止输入 0
            editor->setValidator(intValidator);
        } else if (type_ == DoubleType) {
            QDoubleValidator *doubleValidator = new QDoubleValidator(editor);
            editor->setValidator(doubleValidator);
        }
        return editor;
    }

    void setEditorData(QWidget *editor, const QModelIndex &index) const override {
        QString value = index.model()->data(index, Qt::EditRole).toString();
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
        lineEdit->setText(value);
    }

    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override {
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
        model->setData(index, lineEdit->text(), Qt::EditRole);
    }

    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
        editor->setGeometry(option.rect);
    }

private:
    DataType type_;
};

class MyTableWidget : public QTableWidget {
Q_OBJECT

public:
    MyTableWidget(QWidget *parent = nullptr) : QTableWidget(parent), isValidating(false) {
        setEditTriggers(QAbstractItemView::DoubleClicked); // 设置为双击编辑
        connect(this, &QTableWidget::cellChanged, this, &MyTableWidget::onCellChanged);

        // 为第一列设置整数代理，禁止 0
        setItemDelegateForColumn(0, new NumericDelegate(NumericDelegate::IntegerType, this));
        // 为第二列设置双精度浮点数代理
        setItemDelegateForColumn(1, new NumericDelegate(NumericDelegate::DoubleType, this));
    }

    void setTableSize(int rows, int columns) {
        setRowCount(rows);
        setColumnCount(columns);
    }

protected:
    void keyPressEvent(QKeyEvent *event) override {
        if (event->key() == Qt::Key_Tab) {
            event->ignore();
            return;
        }

        if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
            int row = currentRow();
            int column = currentColumn();
            if (!validateAndAlert(row, column)) {
                QTimer::singleShot(0, this, [=]() { editItem(item(row, column)); });
                return;
            }
        }
        QTableWidget::keyPressEvent(event);
    }

    void mousePressEvent(QMouseEvent *event) override {
        int row = currentRow();
        int column = currentColumn();
        if (!validateAndAlert(row, column)) {
            QTimer::singleShot(0, this, [=]() { editItem(item(row, column)); });
            return;
        }
        QTableWidget::mousePressEvent(event);
    }

signals:
    void ExpressionFinishSg(const QString &expr, bool &isOk);

private slots:
    void onCellChanged(int row, int column) {
        if (!validateAndAlert(row, column)) {
            QTimer::singleShot(0, this, [=]() { editItem(item(row, column)); });
        }
    }

private:
    bool isValidating;
    QString currentText_;

    bool validateAndAlert(int row, int column) {
        if (isValidating) return true;

        isValidating = true;
        QTableWidgetItem *currentItem = item(row, column);
        if (!currentItem) {
            isValidating = false;
            return true;
        }

        QString expr = currentItem->text();
        bool isOk = true;
        emit ExpressionFinishSg(expr, isOk);

        if (!isOk) {
            if (currentText_ != expr) {
                currentText_ = expr;
                QMessageBox::warning(this, "Invalid Expression", "Please enter a valid expression.");
            }
            setCurrentCell(row, column);
            QTimer::singleShot(0, this, [=]() { editItem(item(row, column)); });
            isValidating = false;
            return false;
        }

        isValidating = false;
        return true;
    }
};

#endif //DEMO2_BASE_TABLE_WIDGET_H
